package com.ds.infrastructure.hyperspace.container.flow.handler.loadbalance;

import com.ds.infrastructure.hyperspace.common.Container;
import com.ds.infrastructure.hyperspace.common.EndpointNode;
import com.ds.infrastructure.hyperspace.common.config.TargetNodeConfig;
import com.ds.infrastructure.hyperspace.common.flow.DuplexFlowContext;
import com.ds.infrastructure.hyperspace.common.flow.FlowHandlerPipeline;
import com.ds.infrastructure.hyperspace.common.flow.TargetNodeWrapper;
import com.ds.infrastructure.hyperspace.common.flow.handler.LoadBalancePreFlowHandler;
import com.ds.infrastructure.hyperspace.container.flow.context.HyperspaceDuplexFlowContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author  Weishaoying
 */
@Slf4j
public class RoundRobinPreHandler implements LoadBalancePreFlowHandler<HyperspaceDuplexFlowContext> {

    private static final int MAX_REWIND_SIZE = 1000000;

    private AtomicInteger currentCount = new AtomicInteger(0);

    @Override
    public EndpointNode<TargetNodeConfig> select(HyperspaceDuplexFlowContext duplexFlowContext,
            List<EndpointNode<TargetNodeConfig>> nodeList,
            Map<String, ? extends TargetNodeWrapper> nodeContextMap) {
        if (CollectionUtils.isEmpty(nodeList)) {
            return null;
        }
        if (nodeList.size() == 1) {
            return nodeList.get(0);
        }

        int index = currentCount.getAndIncrement();
        if (index > MAX_REWIND_SIZE) {
            index = 0;
            currentCount.set(1);
        }

        for (int i = 0; i < nodeList.size(); i++) {
            EndpointNode<TargetNodeConfig> currentNode = nodeList.get((i + index) % nodeList.size());
            if (currentNode.isAvailable()) {
                return currentNode;
            }
        }
        return nodeList.get(index % nodeList.size());
    }

    @Override
    public String handlerName() {
        return "roundrobinPreHandler";
    }

    @Override
    public void initHandlerParameters(Container container, FlowHandlerPipeline pipeline, String[] handlerParams) {
        // no need implements
    }
    @Override
    public void handleInput(DuplexFlowContext duplexFlowContext, Object data) {
        // no need implements
    }
}
